package com.bdqn.qnnews.wemedia.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bdqn.qnnews.common.base.PageResult;
import com.bdqn.qnnews.common.base.ResultCode;
import com.bdqn.qnnews.common.utils.ThreadLocalUtils;
import com.bdqn.qnnews.rest.exception.ApplicationException;
import com.bdqn.qnnews.wemedia.convert.WmNewsConvert;
import com.bdqn.qnnews.wemedia.entity.WmMaterial;
import com.bdqn.qnnews.wemedia.entity.WmNews;
import com.bdqn.qnnews.wemedia.entity.WmNewsMaterial;
import com.bdqn.qnnews.wemedia.mapper.WmMaterialMapper;
import com.bdqn.qnnews.wemedia.mapper.WmNewsMapper;
import com.bdqn.qnnews.wemedia.mapper.WmNewsMaterialMapper;
import com.bdqn.qnnews.wemedia.service.WmNewsService;
import com.bdqn.qnnews.wemedia.vo.AdminNewsListVo;
import com.bdqn.qnnews.wemedia.vo.WmNewsPageReqVo;
import com.bdqn.qnnews.wemedia.vo.WmNewsVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 自媒体图文内容信息表 服务实现类
 * </p>
 *
 * @author xlz
 * @since 2023-12-26
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    private final WmNewsMaterialMapper newsMaterialMapper;
    private final WmMaterialMapper wmMaterialMapper;

    @Override
    public PageResult<List<WmNews>> findList(WmNewsPageReqVo vo) {
        //获取当前登录用户
        String userId = (String) ThreadLocalUtils.get();
        if(userId == null){
            throw new ApplicationException(ResultCode.NEED_LOGIN);
        }

        // 创建一个查询条件对象
        final QueryWrapper<WmNews> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",userId);
        wrapper.ge(vo.getBeginPubDate() != null,"publish_time",vo.getBeginPubDate());
        wrapper.le(vo.getEndPubDate() != null,"publish_time",vo.getEndPubDate());
        wrapper.eq(vo.getStatus() != null,"status",vo.getStatus());
        wrapper.eq(vo.getChannelId() != null,"channel_id",vo.getChannelId());
        wrapper.like(!StringUtils.isEmpty(vo.getKeyword()),"title",vo.getKeyword());
        //排序
        wrapper.orderByDesc("created_time");

        // 构建分页对象
        final Page<WmNews> page = new Page<>(vo.getPage(), vo.getSize());

        // 查询
        final Page<WmNews> pageData = page(page, wrapper);

        //封装分页数据
        return PageResult.ok(ResultCode.SUCCESS,pageData.getRecords())
                .setCurrentPage(vo.getPage())
                .setTotal((int) pageData.getTotal())
                .setSize(vo.getSize());
    }

    @Override
    public PageResult<List<WmNews>> findAdminNewsList(AdminNewsListVo vo) {
        // 创建一个查询条件对象
        final QueryWrapper<WmNews> wrapper = new QueryWrapper<>();
        wrapper.eq(vo.getStatus() != null,"status",vo.getStatus());
        wrapper.like(StringUtils.isNotEmpty(vo.getTitle()),"title",vo.getTitle());
        //排序
        wrapper.orderByDesc("created_time");

        // 构建分页对象
        final Page<WmNews> page = new Page<>(vo.getPage(), vo.getSize());

        // 查询
        final Page<WmNews> pageData = page(page, wrapper);

        //封装分页数据
        return PageResult.ok(ResultCode.SUCCESS,pageData.getRecords())
                .setCurrentPage(vo.getPage())
                .setTotal((int) pageData.getTotal())
                .setSize(vo.getSize());
    }

    // 事务
    @Transactional(rollbackFor = Exception.class)
    @Override
    public WmNews submit(WmNewsVo vo) {
        log.debug("文章发布的原始数据: {}",vo);
        // 将vo转换为entity
        final WmNews wmNews = WmNewsConvert.INSTANCE.voToEntity(vo);

        //获取当前登录用户
        String userId = (String) ThreadLocalUtils.get();
        if(userId==null){
            throw new ApplicationException(ResultCode.NEED_LOGIN);
        }
        // 绑定用户id
        final long uid = Long.parseLong(userId);
        wmNews.setUserId(uid);

        // 从文章内容中提取内容图片地址
        final List<String> contentImages = getContentImageFromNews(wmNews);
        // 判断当前用户是否为自动设置封面
        if(vo.getType() == -1){
            // 用户勾选了自动设置封面图片
            int size = contentImages.size();

            if (size == 0) {
                // 设置封面图片为单图
                wmNews.setType((byte)0);
            }else if (size == 1 || size == 2){
                // 设置封面图片为单图
                wmNews.setType((byte)1);
                //取出第一张图片
                wmNews.setImages(contentImages.get(0));
            }else {
                // 设置封面图片为单图
                wmNews.setType((byte)3);
                //取出前三张图片
                final List<String> subList = contentImages.subList(0, 3);
                // 将图片集合拼接为字符串，然后添加到news对象中
                wmNews.setImages(String.join(",", subList));
            }
        }else {
            // 用户自己提交了封面图片
            final List<String> images = vo.getImages();
            if (images != null){
                // 将图片集合拼接为字符串，然后添加到news对象中
                wmNews.setImages(String.join(",", images));
            }
        }

        // 判断当前是新增还是修改
        if (vo.getId() == null){
            // 新增
            wmNews.setCreatedTime(LocalDateTime.now());
            // 保存数据到mysql数据库
            save(wmNews);
        }else {
            // 修改
            updateById(wmNews);

            // 修改前先把文章素材之前的关联数据清空
            newsMaterialMapper.delete(Wrappers
                    .<WmNewsMaterial>lambdaQuery()
                    .eq(WmNewsMaterial::getNewsId, vo.getId()));
        }

        // 处理news内容图片和素材表的关联关系
        // 1.先获取素材对应的id
        final List<Long> ids = getMaterialIdsFromUrl(contentImages);
        if (CollectionUtil.isNotEmpty(ids)){
            /*
        1. 素材 id
        2. 文章 id
        3. 引用类型	0 内容引用	1 主图（封面）引用
         */
            newsMaterialMapper.insertBatch(ids, wmNews.getId(), 0);
        }
        // 处理news封面图片和素材表的关联关系
        // 封面图片需要从news里面去获取，因为需要保证封面图片在自动模式下已经设置完成

        final String images = wmNews.getImages();
        if(StringUtils.isNotEmpty(images)) {
            // 将前面已经处理好的封面图片字符串再反向转换为集合
            final String[] imgsList = images.split(",");
            final List<Long> coverMaterialIds = getMaterialIdsFromUrl(Arrays.asList(imgsList));
            if (CollectionUtil.isNotEmpty(coverMaterialIds)) {
                /*
                1. 素材 id
                2. 文章 id
                3. 引用类型	0 内容引用	1 主图（封面）引用
                 */
                newsMaterialMapper.insertBatch(ids, wmNews.getId(), 1);
            }
        }
        return wmNews;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean deleteNewsById(Long id) {
        // 1. 删除文章数据
        removeById(id);
        // 2. 清空素材关联表数据
        // 修改前先把文章素材之前的关联数据清空
        newsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery()
                .eq(WmNewsMaterial::getNewsId, id));

        return true;
    }

    /**
     * 根据素材的URL查询素材ID
     * @param images
     * @return
     */
    private List<Long> getMaterialIdsFromUrl(List<String> images) {
        if(CollectionUtils.isNotEmpty(images)){
            // 制定查询条件，根据图片url查询对应的id
            QueryWrapper<WmMaterial> queryWrapper = new QueryWrapper<>();
            // 批量查询，通过in来输入多个地址
            queryWrapper.in("url",images);
            // 返回素材信息列表
            List<WmMaterial> wmMaterials = wmMaterialMapper.selectList(queryWrapper);

            if(CollectionUtils.isNotEmpty(wmMaterials)){
                // 通过lambda表达式和stream流将素材对象列表转换为素材id列表
                return wmMaterials.stream()
                        .map(WmMaterial::getId)
                        .collect(Collectors.toList());
            }
        }
        return null;
    }

    /**
     * 获取文章内容的所有图片
     * @param wmNews
     * @return
     */
    private List<String> getContentImageFromNews(WmNews wmNews) {
        // 创建一个字符串列表对象，保存图片地址
        List<String> contentImages = new ArrayList<>();
        // 如果当前文章内容不为空
        if(StringUtils.isNotEmpty(wmNews.getContent())){
            // 将文章内容字符串转换为对象
            List<Map> list = JSONUtil.toList(wmNews.getContent(), Map.class);
            for(Map map:list){
                // 如果内容的type类型是图片，就保存对应的值
                if("image".equals(map.get("type"))){
                    contentImages.add((String)map.get("value"));
                }
            }
        }
        return contentImages;
    }
}
